# -*- coding:utf-8 -*-
"""
Created on May 31, 2011

"""
from numpy.lib.scimath import sqrt
import copy
class CenterOfMass():
    
    DEBUG = False
    
    def __init__(self, player, N, board, isFirstBoard):
        '''
        @param player: the player for which the center of mass i calculated
        @param N: the size of the board
        @param board: the current board state
        @param isFirstBoard: optimization! if first board - the center of mass is known 
        '''
        self.player     = player
        self.N          = N
        self.calcCenter(board) #calculates the center and the #pieces as a sideffect 

    def clone(self):
        new = copy.deepcopy(self)
        return new 
    
    def sumOfDistancesFromCOM(self, state):
        '''
        Calculate the sum of distances from the center of the mass
        @requires: the negative value of the sum of distances from the center of the mass 
        '''
        penalty = 0
        count   = 0
        done    = False 
        for i in xrange(0,self.N):
            for j in xrange(0, self.N):
                if state.board[i][j] == self.player:
                    #the penalty for each piece is the distance to the actual center of mass
                    penalty += sqrt((i - self.centerRow)**2 + (j - self.centerCol)**2)
                    count   += 1
                if count == self.pieces:
                    #optimization - if found all pieces - break
                    done = True
                    break
            if done:
                break
        #the penalty is the negative value of the sum of distances to the center of mass
        return penalty
    
    def calcCenter(self, board):
        '''
        Calculate the center off mass of the given board
        @param board: the board for which the center is calculated
        @return: the (row, col) of the center of mass
        '''
        self.pieces = 0     #number of player pieces
        centerRow   = 0     #the row of the center of mass
        centerCol   = 0     #the col of the center of mass
        #iterate over the board
        for i in xrange(0,self.N):
            for j in xrange(0, self.N):
                if board[i][j] == self.player:
                    self.pieces += 1
                    centerCol   += j
                    centerRow   += i
        
        centerCol /= self.pieces
        centerRow /= self.pieces
        self.centerCol = centerCol
        self.centerRow = centerRow
        ###########DEBUG###########
        if self.DEBUG:
            print "Center of Mass::Calc Center. Number of pieces: ",self.pieces
        ###########################
        return (self.centerRow, self.centerCol)
                    
    def changeCenter(self, oldPos, newPos):
        '''
        make the change to the center of mass caused be the move oldPos -> newPos  
        
        @param oldPos: a (row,col) tuple of the old position of a piece
        @param newPos: a (row,col) tuple of the new position of a piece
        @return: center of mass after change
        '''
        if not oldPos is None: 
            self.centerCol -= (oldPos[1]/self.pieces)
            if not newPos is None: 
                self.centerCol += (newPos[1]/self.pieces)
        if not newPos is None: 
            self.centerRow -= (oldPos[0]/self.pieces)
            self.centerRow += (newPos[0]/self.pieces)
        return (self.centerRow, self.centerCol)
    
    def eatPiece(self, point):
        '''
        change the center of the mass after a piece was *eaten* be the opponent
         
        @param point: the point where the eaten piece used to be
        @return: the center of mass after the change
        '''
        ###########DEBUG###########
        if self.DEBUG:
            print "Center of mass::Eat Piece: before", self.pieces, " after: ", self.pieces - 1
        ###########################
        #change the number of pieces and remove the eaten piece
        self.centerCol *= self.pieces
        self.centerCol -= point[1]
        self.centerRow *= self.pieces
        self.centerRow -= point[0]
        self.pieces    -= 1
        #calculate new center of mass
        if self.pieces == 0:
            self.centerCol = 0
            self.centerRow = 0
        else:
            self.centerCol /= self.pieces
            self.centerRow /= self.pieces
        #add to the center of mass the change caused by the move of the piece
        return self.changeCenter(point, None)
    
#from loa_game import BLACK, EMPTY, WHITE
#size = 8
#board = (   (' ', 'W', 'W', 'W', 'W', 'W', 'W', ' '),
#            (' ', ' ', ' ', ' ', ' ', 'B', 'B', ' '),
#            (' ', ' ', ' ', ' ', ' ', 'B', 'B', ' '),
#            (' ', ' ', ' ', ' ', ' ', 'B', ' ', ' '),
#            (' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '),
#            (' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '),
#            (' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '),
#            (' ', 'W', 'W', 'W', 'W', 'W', 'W', ' '))
#
#class state:
#    def __init__(self,board):
#        self.board = board
#c = CenterOfMass(BLACK, 8, board, True)
#print "BLACK Center: (", c.centerRow,",", c.centerCol, ") Pieces: ", c.pieces
#print "BLACK penalty: ", c.utility(state(board))
#c = CenterOfMass(WHITE, 8, board, True)
#print "WHITE Center: (", c.centerRow,",", c.centerCol, ") Pieces: ", c.pieces
#print "WHITE penalty: ", c.utility(state(board))

